__DefBitFieldType BARMode<1>
    SYNC;
    ARV;
    // RED;

__DefBitFieldType BARREDOp<2>
    AND;
    OR;
    POPC;

__DefBitFieldType B2RMode<1>
    WARP;
    BAR;

__DefGroup BCU : [ALL]
  __Encoding
    field<12, 3> Pred pg=PT;
    field<15, 1> PModi pg.not=False;

  __Examples
```
BAR.SYNC 0x0 ; //
BAR.ARV 0x1, 0x80 ;
BAR.ARV 0x1, R5 ;
BAR.ARV R4, 0x80 ;
BAR.ARV R5, R5 ;    // => BAR.ARV R5, R5;
BAR.SYNC R7, R7 ;   // => BAR.SYNC R7, R7;
BAR.SYNC R4 ;

BAR.RED.OR 0x0, P0 ;
BAR.RED.AND 0x1, 0x80, P0 ;
BAR.RED.AND 0x1, R5, P0 ;
BAR.RED.AND R4, P0 ;
BAR.RED.AND R4, 0x80, P0 ;
BAR.RED.AND R5, R5, P0 ;

B2R.RESULT RZ, P0 ;
B2R.RESULT R4 ;
B2R.BAR R4, 0x2;
B2R.WARP R4;

R2B.WARP R4;
R2B.BAR 0x4, R4;
```

__DefOptype BAR : [BCU]
  __Encoding
    field<0,  8> Optype optype==BAR;
    field<80, 1> BARMode mode;

  __Syntax
```asm          
BAR.SYNC SrcBarId, SrcCnt      $sched $req ;
BAR.ARV  SrcBarId, SrcCnt      $sched $req ;
```

  __Description
使用barrier进行CTA内的同步操作：
- BAR.SYNC表明执行线程抵达barrier，更新barrier计数，同时阻塞执行线程，直至barrier计数达到预期值
- BAR.ARV 表明执行线程抵达barrier，仅更新barrier计数，不阻塞执行线程

当barrier计数达到SrcCnt指定的预期值时，会自动唤醒被阻塞线程，同时将barrier计数清零。

当存在warp divergence时，由于BAR指令本身不具备切换到同一warp其他线程的功能，线程如果因为执行BAR指令发生阻塞，就相当于整个warp都发生了阻塞。

  __OperandInfo
输入操作数SrcBarId表示同步操作所使用的barrier的编号，合法的取值只能是4位的整数0~15。

输入操作数SrcCnt表示barrier完成时预期达到的计数值，合法的取值只能是12位无符号整数，且必须是32的倍数:
- BAR.SYNC指令中，允许SrcCnt = 0，表示预期所有alive的warp都参与barrier同步，具体语义请参考Semantics部分的BAR.SYNC小节
- BAR.ARV 指令中，要求SrcCnt > 0，表示预期的barrier计数最终值，具体语义请参考Semantics部分的BAR.ARV小节

SrcBarId和SrcCnt二者的合法来源组合包括：

| SrcBarId | SrcCnt |  
|:----------|:--------|
| UImm4 | UImm12 |
| GPR | GPR |
| GPR | UImm12 |
| UImm4 | GPR |

如果SrcBarId的来源位宽大于4位，则只有最低的4bit是有效的。

如果SrcCnt的来源位宽大于12位，则只有最低的12bit是有效的。

  __ModifierInfo
BAR.SYNC和BAR.ARV具有截然不同的语义，请参考Semantics部分。

  __Semantics
BAR指令只能用于对同一个CTA内的线程进行同步，以下讨论都只针对同一CTA进行。

### BAR.SYNC

同一个warp内执行的一条BAR.SYNC指令会对SrcBarId指定的barrier计数加32，同时检查SrcCnt的值：
- 如果SrcCnt = 0
  - 如果：barrier计数 + 已经完全退出的warp数 * 32 = CTA内线程总数，则不发生阻塞
  - 否则，阻塞当前线程，直至满足上面的条件
- 如果SrcCnt > 0
  - 如果：barrier计数 = SrcCnt，则不发生阻塞
  - 否则，阻塞当前线程，直至满足上面的条件

BAR.SYNC指令带有内存屏障的语义，针对的是那些可以被同一CTA内所有线程访问的内存空间：
- 执行线程在BAR.SYNC指令之前发出的读请求，在BAR.SYNC指令完成后必定完成
- 执行线程在BAR.SYNC指令之前发出的写请求，在BAR.SYNC指令完成后必定完成

### BAR.ARV

同一个warp内执行的一条BAR.ARV指令会对SrcBarId指定的barrier计数加32，然后可以继续执行BAR.ARV的下一条指令

相互配合（使用相同barrier）的BAR.ARV和BAR.SYNC指令所使用的SrcBarId和SrcCnt的值必须严格相等，否则会引发运行时异常。

  __Examples
```asm
BAR.SYNC 0x0, 0x40 ;
BAR.SYNC  R0, R1   ;
BAR.ARV  0x0, R1   ;
```

__DefOpcode BAR_I : [BAR]
  __Encoding
    field<8,   4> SType stype==I;

    field<40,  4> UImm4 barid;
    field<44, 12> UImm12 cnt;
  __OperandInfo
    InList<pg>;
    OutList<>;
    Order<pg, barid, cnt>;
    Bitwidth<barid> = 4;
    Bitwidth<cnt> = 12;

__DefOpcode BAR_RR : [BAR]
  __Encoding
    field<8,   4> SType stype==R;
    field<32,  8> Reg rb;
    field<24,  8> Reg ra;
  __OperandInfo
    InList<pg, ra, rb>;
    OutList<>;
    Order<pg, ra, rb>;
    Bitwidth<ra> = 32;
    Bitwidth<rb> = 32;

__DefOpcode BAR_RRI : [BAR]
  __Encoding
    field<8,   4> SType stype==RRI;
    field<32,  8> Reg rb;
    field<44, 12> UImm12 cnt;
  __OperandInfo
    InList<pg, rb>;
    OutList<>;
    Order<pg, rb, cnt>;
    Bitwidth<rb> = 32;
    Bitwidth<cnt> = 12;

__DefOpcode BAR_RIR : [BAR]
  __Encoding
    field<8,   4> SType stype==RIR;
    field<32,  8> Reg rc;
    field<40,  4> UImm4 barid;
  __OperandInfo
    InList<pg, rc>;
    OutList<>;
    Order<pg, barid, rc>;
    Bitwidth<barid> = 4;
    Bitwidth<rc> = 32;

__DefOptype BAR_RED : [BCU]
  __Encoding
    field<0,  8> Optype optype==BAR_RED;

    field<80, 2> BARREDOp redop;

    field<98, 3> Pred pp;
    field<101, 1> PModi pp.not=False;

  __Syntax
```asm          
BAR.RED.redop SrcBarId, SrcCnt, {!}pp      $sched $req ;  // 3操作数版本
BAR.RED.redop               Rb, {!}pp      $sched $req ;  // 2操作数版本

redop = {.AND, .OR, .POPC}
```

  __Description
使用barrier进行CTA内的同步和归约（reduction）操作：
- 执行BAR.RED表明执行线程抵达barrier，更新barrier计数，同时阻塞，等待barrier计数达到预期值
- barrier计数达到预期值后，对所有抵达barrier的线程的谓词pp进行指定的归约
- 稍后，归约结果可在参与同步的线程中使用B2R.RESULT指令获取
- 归约完成后，唤醒所有被阻塞的线程，同时将barrier计数清零

由于BAR.RED指令本身不具备切换到同一warp其他线程的功能，线程如果因为执行该指令发生阻塞，就相当于整个warp都发生了阻塞。

  __OperandInfo
根据操作数的数量不同，可以区分3操作数版本和2操作数版本。

二者的不同主要在于如何用操作数指定同步所用的barrier编号和预期达到的计数。

最后一个操作数pp表示参与归约的谓词输入，必须来源于PR。

pp可以选择添加一个逻辑非（！）前缀作为修饰符，表示对来源取反作为输入。

### 3操作数版本

操作数SrcBarId表示同步操作所使用的barrier的编号，合法的取值只能是4位的整数0~15。

操作数SrcCnt表示barrier完成时预期达到的计数值，合法的取值只能是12位无符号整数，且必须是32的倍数:
- 如果SrcCnt = 0，表示预期所有alive的warp都参与barrier同步，具体语义请参考Semantics部分
- 如果SrcCnt > 0，表示预期的barrier计数最终值，具体语义请参考Semantics部分

SrcBarId和SrcCnt二者的合法来源组合包括：

| SrcBarId | SrcCnt |  
|:----------|:--------|
| UImm4 | UImm12 |
| GPR | UImm12 |
| UImm4 | GPR |

如果SrcBarId的来源位宽大于4位，则只有最低的4bit是有效的。

如果SrcCnt的来源位宽大于12位，则只有最低的12bit是有效的。

### 2操作数版本

操作数Rb必须是GPR，用Rb的低4bit作为barrier的编号，接下来的12bit作为barrier完成时预期达到的计数值。

  __ModifierInfo
.redop修饰符用于指定归约计算的类型：

| .redop | 说明 |
|:----|:-----|
|.AND | 对所有输入谓词进行逻辑与计算 |
|.OR  | 对所有输入谓词进行逻辑或计算 |
|.POPC| 对所有输入谓词计算popcount |

逻辑与、逻辑或归约计算的结果都是一个布尔值（true或false）。

popcount(即population count的简写)也就是计算所有值为true的输入个数，结果是一个无符号整数。

  __Semantics
BAR.RED指令只能用于对同一个CTA内的线程进行同步和归约。

下面的讨论中，将barrier的编号记作barId，期望达到的计数值记作cnt。

### barrier计数规则

同一个warp内执行的一条BAR.RED指令会对编号为barId的barrier计数加32。

存在分支时，同一条指令可能只被warp内一部分（少于32）线程执行，但是barrier计数仍然会增加32。

### 同步完成条件

根据cnt值的不同，同步完成的条件也不同：
- cnt = 0，完成条件是：barrier计数 + 已经完全退出的warp数 * 32 = CTA内线程总数
- cnt > 0，完成条件是：barrier计数 = cnt

执行BAR.RED指令的线程会在更新barrier计数后，检查是否满足同步完成条件：
- 如果不满足条件，则执行线程会被阻塞
- 如果已满足条件，则继续进行归约计算

### 归约计算

同步完成条件满足后，对所有参与同步的线程输入的谓词pp，按照.redop指定的行为进行归约。

每个参与同步的线程所在的warp都会获得一个包含归约结果的副本，稍后可以用B2R.RESULT指令获取这一结果。

归约计算完成后，解除所有因为参与同步而被阻塞的线程，同时将barrier计数清零。

注意：下一次归约计算会覆盖前一次的结果，因此请及时使用B2R.RESULT指令获取每一次归约结果。

### 内存屏障

BAR.RED指令带有内存屏障的语义，针对的是那些可以被同一CTA内所有线程访问的内存空间：
- 执行线程在BAR.RED指令之前发出的读请求，在BAR.RED指令完成后必定完成
- 执行线程在BAR.RED指令之前发出的写请求，在BAR.RED指令完成后必定完成

### 注意事项

BAR.RED指令不能和BAR.SYNC、BAR.ARV指令使用相同的barrier编号，否则会产生运行时异常。

  __Examples
```asm
BAR.RED.POPC 0x0, 0x40,  PT; // 在64个线程之间进行popcount归约
BAR.RED.OR          R0, !P1; // 使用barId=R0 & 0xF的barrier，在cnt=(R0 & 0xFFF)>>4个线程之间进行逻辑或归约
```

__DefOpcode BAR_RED_I : [BAR_RED]
  __Encoding
    field<8,   4> SType stype==I;

    field<40,  4> UImm4 barid;
    field<44, 12> UImm12 cnt;
  __OperandInfo
    InList<pg, pp>;
    OutList<>;
    Order<pg, barid, cnt, pp>;
    Bitwidth<barid> = 4;
    Bitwidth<cnt> = 12;

__DefOpcode BAR_RED_R : [BAR_RED]
  __Encoding
    field<8,   4> SType stype==R;
    field<32,  8> Reg rb;
  __OperandInfo
    InList<pg, rb, pp>;
    OutList<>;
    Order<pg, rb, pp>;
    Bitwidth<rb> = 32;

__DefOpcode BAR_RED_RRI : [BAR_RED]
  __Encoding
    field<8,   4> SType stype==RRI;

    field<32,  8> Reg rb;
    field<44, 12> UImm12 cnt;
  __OperandInfo
    InList<pg, rb, pp>;
    OutList<>;
    Order<pg, rb, cnt, pp>;
    Bitwidth<rb> = 32;
    Bitwidth<cnt> = 12;

__DefOpcode BAR_RED_RIR : [BAR_RED]
  __Encoding
    field<8,   4> SType stype==RIR;
    field<32,  8> Reg rc;
    field<40,  4> UImm4 barid;
  __OperandInfo
    InList<pg, rc, pp>;
    OutList<>;
    Order<pg, barid, rc, pp>;
    Bitwidth<barid> = 4;
    Bitwidth<rc> = 32;

__DefOptype B2R : [BCU]
  __Encoding
    field<0,  8> Optype optype==B2R;
    field<16, 8> Reg rd;
    field<80, 1> B2RMode mode;

  __Syntax
```asm          
B2R.mode Rd, UImm4BarId      $sched $req $wsb ;

.mode = {.BAR, .WARP}
```

  __Description
获取指定的barrier当前状态信息，写入一个32bit寄存器中。

  __OperandInfo
32bit输出寄存器Rd用于保存barrier的状态信息，必须来源于GPR。

UImm4BarId是一个UImm4立即数，指定要获取的barrier的编号，因此合法值只能是0~15。

UImm4BarId只在.mode = .BAR的模式下有效，其他情况下不发挥作用。

  __ModifierInfo
.mode修饰符可取值是.BAR或者.WARP：
- .BAR ：获取指定的barrier的状态信息
- .WARP：获取当前warp所参与的上一次BAR.RED归约计算的状态信息

具体解释请参考下面的Semantics部分。

  __Semantics
每个CTA有16个可用的barrier，编号为0~15。

每个barrier有自己的状态信息，通过这些信息来执行线程同步等功能。

由于BAR.RED也是通过CTA内某个barrier进行同步和归约的，因此一个warp参与的归约计算的状态信息就来自上一个BAR.RED指令所使用的barrier。

因此，若在B2R.WARP之前尚未执行任何归约计算，该指令获得的结果是未定义的。

```asm
B2R.BAR Rd, UImm4BarId:
    Rd = getBarState(UImm4BarId);

B2R.WARP Rd, UImm4BarId:
    // 检查当前warp是否参加过BAR.RED归约：
    if (isRedPerformed()) {
        // 获取上一次参加的BAR.RED所用的barrier ID
        barId = getLatestRedBarId();
        // 获取barrier状态
        Rd = getBarState(barId);
    }
    // 否则，返回值Rd处于未定义状态
```

  __Examples
```asm
B2R R0, 0x0;         // 默认为BAR模式，R0=BARState[0]
B2R.WARP R0, 0x0;    // WARP模式将当前WARP的临时WarpBARState存入R0，忽略输入的BarId
                     // WarpBARState是BAR_RED完成同步后自动下发，其他情形为未定义行为。

B2R.BAR R0, 0x0;     // 获取barrier-0的状态

BAR.RED.POPC 0x1, 0x40, PT; // 在64个线程之间进行popcount归约
...
B2R.WARP R1, 0x4;    // 获取上次BAR.RED所用barrier-1的状态，此时第2个立即数是不生效的
```

__DefOpcode B2R_I : [B2R]
  __Encoding
    field<8,  4> SType stype==I;
    field<40, 4> UImm4 barid;
  __OperandInfo
    InList<pg>;
    OutList<rd>;
    Order<pg, rd, barid>;
    Bitwidth<rd> = 32;

__DefOptype B2R_RESULT : [BCU]
  __Encoding
    field<0,  8> Optype optype==B2R_RESULT;
    field<16, 8> Reg rd;
    field<106, 3> Pred pu;

  __Syntax
```asm          
BAR.RESULT Rd, pu      $sched $req $wsb ;
```

  __Description
获取BAR.RED指令的上一次归约计算结果。

  __OperandInfo
输出寄存器Rd必须来自GPR，用于获取BAR.RED指令所作的popcount归约的结果（无符号整数）。

输出谓词寄存器pu必须来自PR，用于获取BAR.RED指令所作的逻辑归约的结果。

关于BAR.RED所作归约计算的类型，可以参考[[BAR_RED]]。

  __Semantics
如[[BAR_RED]]的Semantics部分所言，
BAR.RED指令完成归约后，所有参与归约的warp会获得一个保存结果的副本。

BAR.RESULT指令用于获取当前warp内的副本信息。

因此，若在BAR.RESULT之前尚未执行任何归约计算，该指令获得的结果是未定义的。

BAR.RESULT指令获得的是当前warp最近一次参加并完成的归约计算结果：
- 最近执行的是逻辑归约（逻辑或/逻辑与），只有pu的结果是有意义的，Rd的结果未定义
- 最近执行的是popcount归约，只有Rd的结果是有意义的，pu的结果未定义

  __Examples
```asm
BAR.RED.POPC 0x0, 0x40, PT; // 在64个线程之间进行popcount归约
BAR.RESULT R0, PT;     // 获取归约结果，写入R0，并舍弃谓词输出
```

__DefOpcode B2R_RESULT_X : [B2R_RESULT]
  __Encoding
    field<8,  4> SType stype==X;
  __OperandInfo
    InList<pg>;
    OutList<rd, pu>;
    Order<pg, rd, pu>;
    Bitwidth<rd> = 32;

__DefOptype R2B : [BCU]
  __Encoding
    field<0,  8> Optype optype==R2B;
    field<24, 8> Reg ra;
    field<80, 1> B2RMode mode;

  __Syntax
```asm          
R2B.mode UImm4BarId, Ra      $sched $req ;

.mode = {.BAR, .WARP}
```

  __Description
用一个32bit寄存器Ra，去设置指定的barrier状态信息。

  __OperandInfo
UImm4BarId是一个UImm4立即数，指定要设置的barrier的编号，因此合法值只能是0~15。

UImm4BarId只在.mode = .BAR的模式下有效，其他情况下不发挥作用。

32bit输入寄存器Ra用于设置barrier的状态信息，必须来源于GPR。

  __ModifierInfo
.mode修饰符可取值是.BAR或者.WARP：
- .BAR ：设置指定的barrier的状态信息
- .WARP：设置当前warp所持有的上一次BAR.RED归约计算的状态信息的本地副本

具体解释请参考下面的Semantics部分。

  __Semantics

R2B相当于B2R的逆过程，是将GPR的值存入BARState寄存器（参考[[B2R]]）。也有BAR/WARP两种模式。R2B只在保存和恢复程序上下文时才会使用，一般不出现在用户程序中。

### R2B.BAR
每个CTA有16个可用的barrier，编号为0~15。

每个barrier有自己的状态信息，通过这些信息来执行线程同步等功能。

通过R2B.BAR指令，可以设置指定的barrier的这些状态信息。

### R2B.WARP

BAR.RED也是通过CTA内某个barrier进行同步和归约的。

归约计算完成时，每个参与的warp都会保存一份该barrier状态信息的副本，如[[BAR_RED]]所说，归约结果也保存至这个副本中。

通过R2B.WARP指令，可以获得这个本地副本。

```asm
R2B.BAR UImm4BarId, Ra:
    // 设置CTA内由UImm4BarId指定的barrier的状态：
    setBarState(UImm4BarId, Ra);

R2B.WARP UImm4BarId, Ra:
    // 设置当前warp的本地BAR.RED状态信息副本：
    setWarpBarState(Ra);
```

  __Examples
```
R2B 0x0, R0;    // 默认为BAR模式，BARState[0]=R0
R2B.WARP R0;    // WARP模式将R0存入当前WARP的临时WarpBARState中，忽略输入的BarId

R2B.BAR 0x0, R0;     // 用R0设置barrier-0的状态
BAR.RED.POPC 0x1, 0x40, PT; // 在64个线程之间进行popcount归约
...
R2B.WARP 0x4, R1;    // 用R1设置上次BAR.RED的状态信息的本地副本，此时第1个立即数是不生效的
```

__DefOpcode R2B_RI : [R2B]
  __Encoding
    field<8,  4> SType stype==RI;
    field<40, 4> UImm4 barid;
  __OperandInfo
    InList<pg, ra>;
    OutList<>;
    Order<pg, barid, ra>;
    Bitwidth<ra> = 32;

